package graphiceditor;

import graphiceditor.interfaces.IMememnto;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.List;

import javax.swing.JPanel;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

public class DrawingPanel extends JPanel {
    private static final long serialVersionUID = -7960313735425233155L;

    private List<ShapeWithColor> shapes = Lists.newArrayList();
    private EventBus eventBusForStateChanges = new EventBus(
	    "Bus for publishing status");
    private ShapeWithColor currentShape;

    private ShapeType shapeType = ShapeType.LINE;
    private Color colorType = Color.BLACK;
    private int operationId = 0;

    public DrawingPanel() {
	super();

	addMouseListener(new MouseAdapter() {
	    @Override
	    public void mousePressed(MouseEvent e) {
		if (e.getButton() == MouseEvent.BUTTON1) {
		    System.err.println("Start drag");
		    currentShape = shapeType.createFigure(e.getX(), e.getY(),
			    colorType);
		}
	    }

	    @Override
	    public void mouseReleased(MouseEvent e) {
		if (e.getButton() == MouseEvent.BUTTON1) {
		    System.err.println("Droped");
		    if (shapeType.isValid(currentShape)) {
			shapes.add(currentShape);
			sendMemento();
		    }
		    currentShape = null;
		    repaint();
		}
	    }

	});

	addMouseMotionListener(new MouseMotionAdapter() {
	    @Override
	    public void mouseDragged(MouseEvent e) {
		if (currentShape != null) {
		    System.err.println("Dragging");
		    shapeType.changeShapeBounds(e.getX(), e.getY(),
			    currentShape);
		    repaint();
		}
	    }
	});

    }

    @Override
    public void paint(Graphics g) {
	super.paint(g);
	g.setColor(new Color(255, 0, 0));
	System.err.println("Drawing");
	Graphics2D g2 = (Graphics2D) g;
	for (ShapeWithColor shape : shapes) {
	    drawShape(g2, shape);
	}

	if (currentShape != null) {
	    drawShape(g2, currentShape);
	}
    }

    private void drawShape(Graphics2D g2, ShapeWithColor shapeWithColor) {
	g2.setColor(shapeWithColor.getColor());
	g2.draw(shapeWithColor.getShape());
    }

    @Subscribe
    public void shapeTypeChanged(ShapeType newShapeType) {
	System.err.println("Shape type changed");
	shapeType = newShapeType;
    }

    @Subscribe
    public void colorTypeChanged(Color newColor) {
	System.err.println("Color changed");
	colorType = newColor;
    }

    @Subscribe
    public void setState(Memento newMemento) {
	System.err.println("update memento");
	shapes.clear();
	shapes.addAll(newMemento.items);
	repaint();
    }

    public void subscribeOnChanges(Object subscriber) {
	eventBusForStateChanges.register(subscriber);
    }

    public IMememnto getInitialMemento() {
	return new Memento("Empty drawing",
		Lists.<ShapeWithColor> newArrayList());
    }

    private void sendMemento() {
	eventBusForStateChanges
		.post(new Memento(shapeType.getName()
			+ " added " + ++operationId, shapes));
    }

    private static class Memento implements IMememnto {

	private String descr;
	private ImmutableList<ShapeWithColor> items;

	public Memento(String desription, List<ShapeWithColor> shapes) {
	    descr = desription;
	    items = ImmutableList.copyOf(shapes);
	}

	@Override
	public String toString() {
	    return descr;
	}

    }

}
